#include <51func.h>
typedef struct connInfo_s {
    int fd;
    int isValid; // 0 未使用or已经关闭 1 正在使用的
    time_t lastActive;
} connInfo_t;
int main(int argc, char *argv[])
{
    // ./1_azhen 192.168.118.128 1234
    ARGS_CHECK(argc,3);
    // socket
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(atoi(argv[2]));
    serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
    // setsockopt
    int arg = 1; // REUSEADDR的参数值为真
    int ret = setsockopt(sockfd,SOL_SOCKET,
                         SO_REUSEADDR,&arg,sizeof(arg));
    ERROR_CHECK(ret,-1,"setsockopt");
    // bind
    ret = bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr));
    ERROR_CHECK(ret,-1,"bind");
    // listen
    listen(sockfd,10);
    
    connInfo_t connInfo[1024];//存储所有客户端连接的信息
    for(int i = 0; i < 1024; ++i){
        connInfo[i].isValid = 0;
    }
    int curidx = 0; //下一个要放入的netfd的下标
    // 设计一个数据结构 已知netfd 得到在connInfo数组当中的下标
    int fd2idx[1024];
    for(int fd = 0; fd < 1024; ++fd){
        fd2idx[fd] = -1;
    }
    char buf[4096];
    int epfd = epoll_create(1);
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = sockfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&event);
    struct epoll_event readyset[1024];
    while(1){
        int readynum = epoll_wait(epfd,readyset,1024,1000);
        time_t curtime = time(NULL);
        printf("curtime = %s\n", ctime(&curtime));
        for(int i = 0; i < readynum; ++i){
            if(readyset[i].data.fd == sockfd){
                int netfd = accept(sockfd,NULL,NULL);
                printf("client is connected!, curidx = %d\n", curidx);
                connInfo[curidx].fd = netfd;
                connInfo[curidx].isValid = 1;
                connInfo[curidx].lastActive = time(NULL);
                fd2idx[netfd] = curidx;
                event.events = EPOLLIN;
                event.data.fd = netfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,netfd,&event);
                ++curidx;
            }
            else{
                //某个netfd来消息了 
                int j = fd2idx[readyset[i].data.fd];
                bzero(buf,sizeof(buf));
                ssize_t sret = recv(readyset[i].data.fd,buf,sizeof(buf),0);
                if(sret == 0){
                    //客户端断开连接
                    epoll_ctl(epfd,EPOLL_CTL_DEL,readyset[i].data.fd,NULL);
                    close(readyset[i].data.fd);
                    connInfo[j].isValid = 0;
                    fd2idx[readyset[i].data.fd] = -1;
                    continue;
                }
                for(int k = 0; k < curidx; ++k){
                    if(k == j || connInfo[k].isValid == 0){
                        // k是j本身或者是k已经断开了
                        continue;
                    }
                    send(connInfo[k].fd,buf,strlen(buf),0);
                }
                connInfo[j].lastActive = time(NULL);
            }
        }
        for(int i = 0; i < curidx; ++i){
            if(connInfo[i].isValid == 1 && curtime - connInfo[i].lastActive > 10){
                printf("kick 1 client, i = %d\n", i);
                epoll_ctl(epfd,EPOLL_CTL_DEL,connInfo[i].fd,NULL);
                close(connInfo[i].fd);
                connInfo[i].isValid = 0;
                fd2idx[connInfo[i].fd] = -1;
            }
        }
    }
    return 0;
}

